#ifndef _Ape__Queue_h
#define _Ape__Queue_h

#include <Ape/Object.h>
#include <Ape/Collections/CollectionHelpers.h>

namespace Ape {
	namespace Collections {
		struct QueueJoint;
		
		/**
			base of Queue non-aware of types
			it operates with pointers to the copies of elements (@see Ape::Collections::TypedHelper)
			@warning the collection is not guaranteed to be threadsafe
			@author Roman Gafiyatullin
		*/
		class QueueImpl : public Object {
			TYPE_NAME ("Ape::Collections::QueueImpl")
		private:
			QueueJoint* m_Head;
			QueueJoint* m_Tail;
			size_t m_Count;
		protected:
			/**
				enques an item
				@param pElement item to enqueue
			*/
			void _Enqueue (void* pElement);
			/**
				dequeues an item
				@param noThrow forces this method return NULL instead of throwing an exception when the queue is empty
				@return just dequeued item
				@throw Ape::Exception when the queue is empty and parameter noTrow is false
			*/
			void* _Dequeue (bool noThrow);
		public:
			/**
				ctor
			*/
			QueueImpl();
			/**
				dtor
			*/
			virtual ~QueueImpl();
			
			/**
				count of items in the collection
				@return current count of items
			*/
			size_t get_Count() const;
			
			virtual void _Dump (bool verbose = false) const;
			
			void purge();
			
			virtual void FreePtr (void* p) = 0;
		};
		
		/**
			Type aware Queue
			@warning the collection is not guaranteed to be thread safe
			@author Roman Gafiyatullin
		*/
		template<typename E_t>
		class Queue : public QueueImpl {
			TYPE_NAME ("Ape::Collections::Queue<E_t>")
		private:
		public:
			typedef E_t Element_t;
			
			/**
				ctor
			*/
			Queue() {}
			/**
				dtor
			*/
			virtual ~Queue() {}
			
			/**
				Adds element into the tail of the queue
				@param element Element to enqueue
			*/
			void Enqueue (const E_t& element) {
				void* pElement = TypedHelper<E_t>::ToHeap (element);
				_Enqueue (pElement);
			}
			/**
				Removes and returns an element from the head of the queue
				@return element just dequeued
				@throw Exception when no items left in the queue
			*/
			E_t Dequeue() {
				void* pElement = _Dequeue (false);
				E_t ret = TypedHelper<E_t>::ToStack (pElement);
				TypedHelper<E_t>::Free (pElement);
				return ret;
			}
			/**
				Alias for Ape::Collections::Queue::Enqueue
			*/
			void Enq (const E_t& element) {
				Enqueue (element);
			}
			/**
				Alias for Ape::Collections::Queue::Dequeue
			*/
			E_t Deq() {
				return Dequeue();
			}
			
			virtual void _Dump (bool verbose = false) const {
				QueueImpl::_Dump (verbose);
				DUMP_NON_V_TYPE;
			}
			
			void Purge() {
				purge();
			}
			
		protected:
			virtual void FreePtr (void* p) {
				TypedHelper<E_t>::Free (p);
			}
		};
	}
}

#endif // _Ape__Queue_h
